import { merge, nilV, errorHandle, getErrorMessage, getErrorCode } from "utils";
import { CancelError, DropError } from "../../error";
import { getPromise } from "@/utils/promise";
import { throwIfCancellationRequested, isDropError } from "../tool";
import type { InnerRequestConfig } from "../../types/engine.type";

// 准备请求
const requestFunc = async (
    config: InnerRequestConfig
): Promise<{
    task: UniApp.RequestTask | null;
    response: any;
}> => {
    // 检查  是否要 取消了
    let cancelPromise = throwIfCancellationRequested(config);
    if (cancelPromise) {
        return cancelPromise;
    }
    // 合并header
    let header = merge(config.header ?? {}, config.baseHeader ?? {});
    // 合并data
    let data = merge(config.data ?? {}, config.baseData ?? {});

    let { readyToRequest } = config || {};
    // 哪个云函数
    let cloudName = config.cloudFunction || "";
    let action = config.path ?? "";
    let timeout = config.timeout || 60000;

    // uniCloud 没有 abort 方法
    let { promise, abort } = getPromise<{
        task: UniApp.RequestTask | null;
        response: any;
    }>((resolve, reject) => {
        readyToRequest && readyToRequest(config);
        // 组装 请求
        uniCloud.callFunction({
            name: cloudName,
            data: {
                action,
                request: {
                    header,
                    data,
                },
            },
            // @ts-ignore
            timeout,
            success(res: any) {
                let { result = {} } = res || {};
                // 这里有2种 可能
                // 成功  返回的 是 标准的 { errCode }
                // 失败,  云函数  throw 的错误 / 找不到云函数某个方法的错误 : { code , message }

                // 这里的和  正常的请求不一样, 在这里处理
                let { code } = result || {};
                if (!nilV(code) && code !== 0) {
                    // 出错了
                    let insideErr = errorHandle.insideErr(result);
                    reject && reject(insideErr);
                } else {
                    // 构建和正常 请求一样的响应
                    let finalRes = {
                        data: result || {},
                        statusCode: 200,
                    };
                    resolve(finalRes);
                }
            },
            fail(err: any) {
                // 这里有
                // 没有匹配到  云函数,
                // 超时 / 没有网络
                // 的错误
                let msg = getErrorMessage(err);
                let errMsg = typeof msg === "string" ? msg : null;
                // 超时 或者 没有网络
                let isDrop = isDropError(errMsg);
                if (isDrop) {
                    reject && reject(new DropError());
                    return;
                }
                let insideErr = errorHandle.insideErr(err);
                reject && reject(insideErr);
            },
        });
    });

    if (config.cancelToken) {
        config.cancelToken.promise.then(() => {
            abort();
        });
    }

    try {
        let res = await promise;
        return {
            task: null,
            response: res,
        };
    } catch (error: any) {
        // 可能是  被 abort 了
        let { aborted } = error || {};
        if (aborted === true) {
            // 这个是abort 了
            let reason = config.cancelToken?.reason;
            throw new CancelError(reason);
        } else {
            // 这里的错误 应该都被 处理成 标准的错误了
            throw error;
        }
    }
};

export { requestFunc };
